package com.powerband.apiheartrate.ble.fbkBleController

import android.Manifest
import android.annotation.SuppressLint
import android.app.Application
import android.bluetooth.*
import android.bluetooth.le.ScanCallback
import android.bluetooth.le.ScanFilter
import android.bluetooth.le.ScanResult
import android.bluetooth.le.ScanSettings
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.*
import android.util.Log
import android.util.MutableByte
import androidx.core.app.ActivityCompat
import com.powerband.apiheartrate.base.FBKArmBandCmd
import com.powerband.apiheartrate.base.FBKSummaryType
import com.powerband.apiheartrate.ble.bleCommand.PYBleCommand
import com.powerband.apiheartrate.ble.bleCommand.PYBleCommandType
import com.powerband.apiheartrate.ble.fbkBleDevice.FBKBleDevice
import com.powerband.apiheartrate.ble.fbkBleDevice.FBKBleDeviceStatus
import com.powerband.apiheartrate.heartrate.DataAccessMgr
import com.powerband.apiheartrate.heartrate.LogBufferDelegate
import com.powerband.apiheartrate.tools.FBKSpliceBle
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import no.nordicsemi.android.ble.exception.DeviceDisconnectedException
import no.nordicsemi.android.ble.ktx.state.ConnectionState
import no.nordicsemi.android.ble.ktx.stateAsFlow
import no.nordicsemi.android.ble.ktx.suspend
import no.nordicsemi.android.ble.observer.ConnectionObserver
import java.io.UnsupportedEncodingException
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
import kotlin.math.floor

class FBKBleController(
    var mContext: Application,
    val mBleControllerCallBack: FBKBleControllerCallBack
) : ConnectionObserver {
    private val MAX_TRY = 5
    private var mConnectNumber = 0
    // Stops scanning after 10 seconds.
    private var SCANPERIOD: Long = 5000
    private var isScanning = false
    private val handler = Handler(Looper.getMainLooper())
    private var pageSizeReq = 0
    private var dataType: FBKSummaryType = FBKSummaryType.HeartRate
    private val dataAccessMgr = DataAccessMgr(object : LogBufferDelegate {
        override fun logOutBufferData(data: List<Byte>) {
           mBleControllerCallBack.logOutBufferData(data)
        }
    })

    @Volatile
    var bluetoothDeviceInternal: BluetoothDevice? = null
    var bluetoothLastOne: BluetoothDevice? = null
    private var mDeviceId = ""

    //private var mIsUserDisconnnected = false
    private val mBleCmdManager = FBKBleCmdManager()
    private var mConnectStatus = FBKBleDeviceStatus.BleDisconnected

    @Volatile
    private var mBluetoothAdapter: BluetoothAdapter =
        (mContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
    var mBleListenerReceiver: BroadcastReceiver? = initBroadcastReceiver()
    private val mBleLock: Lock = ReentrantLock()
    private var macDeviceScanned: MutableList<String> = ArrayList()
    private var fbkConnection: FBKConnection? = null


    companion object {
        const val STATE_CHANGED = "android.bluetooth.adapter.action.STATE_CHANGED"
        const val ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED"
        const val ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED"
    }

    private fun refreshBleStatus(status: FBKBleDeviceStatus) {
        mConnectStatus = status
        mBleControllerCallBack.bleConnectStatus(mConnectStatus)
        if (status == FBKBleDeviceStatus.BleDisconnected) {
            clearBleData()
        } else if (status == FBKBleDeviceStatus.BleConnected) {
            mConnectNumber = 0
        }
    }

    fun connectBluetooth(bluetoothDevice: BluetoothDevice, retryTime: Int? = 0) {
        if (fbkConnection != null && (mConnectStatus == FBKBleDeviceStatus.BleConnected
            || mConnectStatus == FBKBleDeviceStatus.BleConnecting)
        ) {
            showLogInfo("device is in connecting $mConnectStatus , con: $fbkConnection")
            return
        }
        clearBleData()
        if (bluetoothDeviceInternal == null) bluetoothDeviceInternal = bluetoothDevice
        bluetoothLastOne = bluetoothDevice
        refreshBleStatus(FBKBleDeviceStatus.BleConnecting)
        MainScope().launch {
            FBKConnection(mContext, bluetoothDevice, connectionCall)
                .apply {
                    connectionObserver = this@FBKBleController
                    fbkConnection = this
                    conectBlue(retryTime ?: 0)
                }
        }
    }

    private val connectionCall = object : FBKConnectionCallback {

        override fun disConnected() {
            refreshBleStatus(FBKBleDeviceStatus.BleDisconnected)
        }

        override fun receiveHeartRate(data: ByteArray?) {
            mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.HeartRate, data)
        }

        override fun connectError(code: Int, msg: String) {
            mBleControllerCallBack.bleConnectError(msg)
            if (code == -2 && bluetoothLastOne != null && mConnectNumber < MAX_TRY) {
                showLogInfo("service is empty , trying to reconnect")
                mConnectNumber++
                connectBluetooth(bluetoothLastOne!!)
            }
        }

        override fun otaDidWriteValue() {
            mBleControllerCallBack.bleDidWriteValue(null)
        }

        override fun receiveBattery(data: ByteArray?) {
            mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.Battery,data)
        }

        override fun receiveNotify(data: ByteArray?) {
            if (data == null) {
                mBleControllerCallBack.bleConnectError("receive wrong notify data")
                return
            }
            when (data.first().toInt()) {
                0x01 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.Threshold, data)
                0x02 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.SyncTime, data)
                0x03 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.Serial, data)
                0x04 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.StepFrequency, data)
                0x05 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.RealTimeOxygen, data)
                0x06 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.PlayStatus, data)
                0x07 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.Reset, data)
                0x08 -> {
                    mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.Unbind, data)
                    disconnectBle()
                }
                0x0a -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.BatteryStatus, data)
                0x0b -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.RateInitial,data)
                0x0d, 0x0e -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.DeviceMode,data)
                0x0f -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.Pressure,data)
                0x10 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.CurrentTime, data)
                0x13 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.SportModeDetail, data)
                0x14 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.DisturbTime, data)
                0x18 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.ExitAlgorithm, data)
                0x19 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.HeartRateLog, data)
                0x21 -> {
                    val total = (data[1].toInt() and 0xFF) or
                            (data[2].toInt() and 0xFF).shl(8) or
                            (data[3].toInt() and 0xFF).shl(16) or
                            (data[4].toInt() and 0xFF).shl(24)
                    // test
                    mBleControllerCallBack.totalPacket(total)
                    dataAccessMgr.total = total
                    dataAccessMgr.page = 0
                    ackToDataSender(0x21)
                }
                0x22 -> {
                    dataAccessMgr.updateData(data)
                    if (dataAccessMgr.page < dataAccessMgr.total) {
                        ackToDataSender(0x22)
                    }
                }
                0x23 -> mBleControllerCallBack.bleSummaryInfo(dataAccessMgr.getDataByType(dataType), dataType)
                0x25 -> {
                    val total = (data[1].toInt() and 0xFF) or
                            (data[2].toInt() and 0xFF).shl(8) or
                            (data[3].toInt() and 0xFF).shl(16) or
                            (data[4].toInt() and 0xFF).shl(24)
                    // test
                    mBleControllerCallBack.totalPacket(total)
                    dataAccessMgr.total = total
                    dataAccessMgr.page = 0
                    ackToDataSender(0x25)
                }
                0x26 -> {
                    dataAccessMgr.updateData(data)
                    if (dataAccessMgr.page < dataAccessMgr.total) {
                        ackToDataSender(0x26)
                    }
                }
                0x27 -> mBleControllerCallBack.bleSummaryInfo(dataAccessMgr.getMotionData(), dataType)
                0x29 -> {
                    val total = (data[1].toInt() and 0xFF) or
                            (data[2].toInt() and 0xFF).shl(8) or
                            (data[3].toInt() and 0xFF).shl(16) or
                            (data[4].toInt() and 0xFF).shl(24)
                    // test
                    mBleControllerCallBack.totalPacket(total)
                    mBleControllerCallBack
                    dataAccessMgr.total = total
                    dataAccessMgr.page = 0
                    ackToDataSender(0x29)
                }
                0x2a -> {
                    dataAccessMgr.updateData(data)
                    if (dataAccessMgr.page < dataAccessMgr.total) {
                        ackToDataSender(0x2a)
                    }
                }
                0x2b -> mBleControllerCallBack.bleSummaryInfo(dataAccessMgr.getMotionData(), dataType)
                0x2d -> {
                    val total = (data[1].toInt() and 0xFF) or
                            (data[2].toInt() and 0xFF).shl(8) or
                            (data[3].toInt() and 0xFF).shl(16) or
                            (data[4].toInt() and 0xFF).shl(24)
                    // test
                    mBleControllerCallBack.totalPacket(total)
                    dataAccessMgr.total = total
                    dataAccessMgr.page = 0
                    ackToDataSender(0x2d)
//                    dataAccessMgr.parseSleepData()
                }
                0x2e -> {
                    dataAccessMgr.updateData(data)
                    if (dataAccessMgr.page < dataAccessMgr.total) {
                        ackToDataSender(0x2e)
                    }
                }
                0x2f -> mBleControllerCallBack.bleSummaryInfo(dataAccessMgr.getSummarySleep(), dataType)
                0x31 -> {
                    val total = (data[1].toInt() and 0xFF) or
                            (data[2].toInt() and 0xFF).shl(8) or
                            (data[3].toInt() and 0xFF).shl(16) or
                            (data[4].toInt() and 0xFF).shl(24)
                    // test
                    mBleControllerCallBack.totalPacket(total)
                    dataAccessMgr.total = total
                    dataAccessMgr.page = 0
                    ackToDataSender(0x31)
                }
                0x32 -> {
                    dataAccessMgr.updateData(data)
                    if (dataAccessMgr.page < dataAccessMgr.total) {
                        ackToDataSender(0x32)
                    }
                }
                0x33 -> mBleControllerCallBack.bleSummaryInfo(dataAccessMgr.getExerciseData(), dataType)
                0x34 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.AckMotion,
                    byteArrayOf(0x00)
                )
                0x35 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.AckMotion,
                    byteArrayOf(0x01)
                )
                0x40 -> mBleControllerCallBack.bleReceivedResult(FBKArmBandCmd.LightControl, data)
                else -> {}
            }
        }
    }

    fun ackToDataSender(data: Byte) {
        writeToBle(byteArrayOf(data))
    }

    fun connectBluetooth(macAddress: String, retryTime: Int? = 0) {
        if ((mConnectStatus === FBKBleDeviceStatus.BleConnected
                    || mConnectStatus === FBKBleDeviceStatus.BleConnecting)
        ) return
        if (BluetoothAdapter.checkBluetoothAddress(macAddress)) {
            val device = mBluetoothAdapter.getRemoteDevice(macAddress)
            refreshBleStatus(FBKBleDeviceStatus.BleConnecting)
            connectBluetooth(device, retryTime)
        } else {
            showLogInfo("mac address invalid")
            mBleControllerCallBack.bleConnectStatus(FBKBleDeviceStatus.BleMacInvalid)
        }
    }

    fun showLogInfo(info: String) {
        mBleControllerCallBack.bleConnectInfo(info)
        mBleControllerCallBack.bleConnectStatusLog(info)
    }

    fun startScan(timeOut: Long? = 5000) {
        if (isScanning) {
            showLogInfo("BluetoothAdapter is already in scanning ===== startScan() returned")
            mBleControllerCallBack.bleScanError("scaning")
            return
        }
        SCANPERIOD = timeOut ?: 5000
        isScanning = true
        if (!mBluetoothAdapter.isEnabled || mConnectStatus == FBKBleDeviceStatus.BleConnected
        ) {
            showLogInfo("BluetoothAdapter not available ===== startScan() returned")
            return
        }
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
            if (ActivityCompat.checkSelfPermission(
                    mContext,
                    Manifest.permission.BLUETOOTH_SCAN
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                showLogInfo("do not have permission BLUETOOTH_SCAN ===== startScan() returned")
                return
            }
        }
        ScanSettings.SCAN_MODE_BALANCED
        macDeviceScanned.clear()
        handler.postDelayed({
            if (isScanning) {
                isScanning = false
                mBluetoothAdapter.bluetoothLeScanner.stopScan(leScanCallback)
                mBleControllerCallBack.onFinishDiscovery()
                showLogInfo("scan time out scan canceled =====")
            }
        }, SCANPERIOD)
        showLogInfo("start scan and  set  time out at $SCANPERIOD")
        var scanSettingsBuild = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).setReportDelay(0L)
                .setPhy(ScanSettings.PHY_LE_ALL_SUPPORTED)
        } else {
            ScanSettings.Builder().setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
           scanSettingsBuild.apply {
               setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
               setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE)
               setNumOfMatches(ScanSettings.MATCH_NUM_ONE_ADVERTISEMENT)
           }
        }
        //TODO - 修改为测试版 6-15-laodai
        //val scanFilters = mutableListOf<ScanFilter>()
//        val heartRateUuid = ParcelUuid.fromString("0000180d-0000-1000-8000-00805f9b34fb")
//        scanFilters.add(ScanFilter.Builder().setServiceUuid(heartRateUuid).build())
        mBluetoothAdapter.bluetoothLeScanner.startScan(null, scanSettingsBuild.build(), leScanCallback)
    }

    fun stopScan() {
        if (!isScanning) {
            return
        }
        if (mBluetoothAdapter.isEnabled
        ) {
            showLogInfo("BluetoothAdapter not available ===== stopScan() returned")
            return
        }
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
            if (ActivityCompat.checkSelfPermission(
                    mContext,
                    Manifest.permission.BLUETOOTH_SCAN
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                showLogInfo("do not have permission BLUETOOTH_SCAN ===== stopScan() returned")
                return
            }
        }
        isScanning = false
        if ( mBluetoothAdapter.bluetoothLeScanner != null) {
            mBluetoothAdapter.bluetoothLeScanner.stopScan(leScanCallback)
        }
        mBleControllerCallBack.onFinishDiscovery()
        showLogInfo("stopScan Devices --- --- ---")
    }


    fun registerBleListenerReceiver() {
        val intentFilter = IntentFilter()
        intentFilter.addAction(STATE_CHANGED)
        intentFilter.addAction(ACL_CONNECTED)
        intentFilter.addAction(ACL_DISCONNECTED)
        mContext.registerReceiver(mBleListenerReceiver, intentFilter)
    }

    fun unregisterBleListenerReceiver() {
        mBleLock.lock()
        try {
            mBleListenerReceiver?.let {
                mContext.unregisterReceiver(it)
            }
        } catch (e: Exception) {
            showLogInfo("unregisterBleListenerReceiver error : $e")
        }
        mBleLock.unlock()
    }
    private fun clearBleData() {
        stopScan()
        bluetoothDeviceInternal = null
        mDeviceId = ""
        // fbkConnection?.refreshDevice()
        fbkConnection?.close()
        fbkConnection = null
    }


    fun toggleNotifyWith(status: Boolean, type: FBKArmBandCmd){
        fbkConnection?.toggleNotifyWith(status,type)
    }

    fun disconnectBle() {
        showLogInfo("call disconnectBle() --- --- --- ")
        MainScope().launch {
            try {
                fbkConnection?.disconnect()?.invalid {
                    mBleControllerCallBack.bleConnectError("断开连接超时")
                }?.suspend()
                fbkConnection?.close()
            } catch (e: DeviceDisconnectedException) {
                mBleControllerCallBack.bleConnectError("DeviceDisconnectedException断开连接失败：${e.localizedMessage}")
            } catch (e: Exception) {
                mBleControllerCallBack.bleConnectError("断开连接失败：${e.localizedMessage}")
            }

        }
    }

    val mtu: Unit
        get() {
            val readCmd = PYBleCommand()
            readCmd.serviceUuid = ""
            readCmd.charUuid = ""
            readCmd.cmdType = PYBleCommandType.BleCmdTypeMTU
            mBleCmdManager.addBleCommand(readCmd)
        }

    fun readCharacteristicValueby(type: FBKArmBandCmd) {
        MainScope().launch {
            mBleControllerCallBack.bleReceivedResult(type, fbkConnection?.readCMD(type)?.value)
        }
    }


    fun writeToBle(cmd: ByteArray) {
        MainScope().launch() {
            fbkConnection?.sendCMD(cmd)
        }
    }


    fun sendOTAData(data: ByteArray) {
        MainScope().launch {

            fbkConnection?.sendOTAPacket(data)
        }
    }

    fun readOTAData() {
        MainScope().launch {
            val data = fbkConnection?.otaReadPacket()?.value
            if (data != null) mBleControllerCallBack.bleDidReadValue(data)
        }
    }
    fun getSummaryData(start: Long, end: Long,type: FBKSummaryType) {
       acuireDataByType(start, end, type)
    }
    private val sDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.CHINA)
    fun acuireDataByType(start: Long, end: Long,type: FBKSummaryType) {
        dataType = type
        var cmd: Byte = 0x20

        //把时间转换成00:00:00
        val zeroStart = Date(start * 1000)
        val zeroEnd = Date(end * 1000)

        val cal = Calendar.getInstance()
        cal.time = zeroStart
        val zeroStartStr = String.format("%04d-%02d-%02d 00:00:00",cal.get(Calendar.YEAR),cal.get(Calendar.MONTH)+1,cal.get(Calendar.DAY_OF_MONTH))
        cal.time = zeroEnd
        val zeroEndStr = String.format("%04d-%02d-%02d 00:00:00",cal.get(Calendar.YEAR),cal.get(Calendar.MONTH)+1,cal.get(Calendar.DAY_OF_MONTH))

        val startZ = ((sDateFormat.parse(zeroStartStr)?.time ?: 0) / 1000.0).toLong()
        val endZ = ((sDateFormat.parse(zeroEndStr)?.time ?: 0) / 1000.0).toLong()

//        if (dataAccessMgr.hasData(startZ, endZ, type)) {
//            when (type) {
//                FBKSummaryType.Sleep ->  mBleControllerCallBack.bleSummaryInfo(dataAccessMgr.getSummarySleep(), dataType)
//                FBKSummaryType.Sport ->  mBleControllerCallBack.bleSummaryInfo(dataAccessMgr.getExerciseData(), dataType)
//                else ->  mBleControllerCallBack.bleSummaryInfo(dataAccessMgr.getDataByType(dataType), dataType)
//            }
//            return
//        }

//        dataAccessMgr.start = startZ
//        dataAccessMgr.end = endZ
        dataAccessMgr.clearData()
        dataAccessMgr.type = type
        if (type == FBKSummaryType.Sleep) {
            cmd = 0x2c
        } else if (type == FBKSummaryType.Sport) {
            cmd = 0x30
        }
        var s = startZ
        var e = endZ
        if (type == FBKSummaryType.Sleep) {
            s -= 24 * 60 * 60
            e -= 24 * 60 * 60
        }
        val startByte = longToByteArray(s)
        val endByte = longToByteArray(e)
        writeToBle(byteArrayOf(cmd) + startByte + endByte)
    }

    fun longToByteArray(value: Long): ByteArray {
        val bytes = ByteArray(8)
        ByteBuffer.wrap(bytes).putLong(value)
        return bytes.copyOfRange(4, 8).reversed().toByteArray()
    }

    fun intToByteArray(value: Int): ByteArray {
        val bytes = ByteArray(8)
        ByteBuffer.wrap(bytes).putInt(value)
        return bytes.copyOfRange(0, 4).reversed().toByteArray()
    }
    fun updateSeq(sportMode:Boolean) {
        val pageByte = intToByteArray(pageSizeReq)
        var cmd: Byte = 0x27
        if (sportMode) {
            cmd = 0x2b
        }
        writeToBle(byteArrayOf(cmd) + pageByte)
    }


    fun getMotionData(pageSize: Int, sportMode:Boolean) {
        var blo = pageSize
         if(sportMode) {
             blo = pageSize / 60
             dataType = FBKSummaryType.ModeSport
        }  else {
             dataType =  FBKSummaryType.ModeDaily
        }
        dataAccessMgr.isSport = sportMode
        dataAccessMgr.type = dataType
        dataAccessMgr.clearData()
        var cmd: Byte = 0x24
        if (sportMode) {
            cmd = 0x28
        }
        pageSizeReq = blo
        val pageByte = intToByteArray(blo)
        writeToBle(byteArrayOf(cmd) + pageByte)

    }
    fun parseAdertisedData(advertisedData: ByteArray?): String? {
        if (advertisedData == null) {
            return ""
        }
        val buffer: ByteBuffer = ByteBuffer.wrap(advertisedData).order(ByteOrder.LITTLE_ENDIAN)
        while (buffer.remaining() > 2) {
            var length: Int = buffer.get().toInt()
            if (length == 0) break
            when (buffer.get().toInt()) {
                0x02, 0x03 -> while (length >= 2) {
                    length -= 2
                }
                0x06, 0x07 -> while (length >= 16) {
                    length -= 16
                }
                0x09 -> {
                    val nameBytes = ByteArray(length - 1)
                    buffer.get(nameBytes)
                    try {
                        return String(nameBytes)
                    } catch (e: UnsupportedEncodingException) {
                        e.printStackTrace()
                    }
                }
                else -> buffer.position(buffer.position() + length - 1)
            }
        }
        return ""
    }
    @OptIn(ExperimentalUnsignedTypes::class)
    @SuppressLint("InlinedApi")
    private fun handleTargetDevice(result: ScanResult): FBKBleDevice? {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
            if (ActivityCompat.checkSelfPermission(
                    mContext,
                    Manifest.permission.BLUETOOTH_CONNECT
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                showLogInfo("do not have permission")
                return null
            }
        }
        var device = result.device
        var name = result.scanRecord?.deviceName
        if (name == null) {
            name = device.name
        }
        return if ( name != null && name.isNotEmpty()) {
            FBKBleDevice(
                device,
                device.name,
                device.address,
                result.rssi,
                result.scanRecord?.bytes
            )
        } else {
            null
        }
    }

    private val leScanCallback: ScanCallback = object : ScanCallback() {
        override fun onScanResult(callbackType: Int, result: ScanResult?) {
            super.onScanResult(callbackType, result)

            result?.let {
                if (macDeviceScanned.contains(it.device.address)) {
                    return
                }
                //Log.d("scan result", "扫描到 $it")
                macDeviceScanned.add(it.device.address)
                val dev = handleTargetDevice(it)
                if (dev != null) {
                    mBleControllerCallBack.onDiscoveryDevice(dev)
                }
            }

        }

        override fun onScanFailed(errorCode: Int) {
            super.onScanFailed(errorCode)
            mBleControllerCallBack.bleScanError("扫描失败")
        }

    }


    private fun handleStateChange(intent: Intent) {
        when (intent.getIntExtra("android.bluetooth.adapter.extra.STATE", 0)) {
            10 -> {
                showLogInfo("BroadcastReceiver BleTurnOff")
                refreshBleStatus(FBKBleDeviceStatus.BleTurnOff)
                disconnectBle()
            }
            13 -> {
                showLogInfo("BroadcastReceiver BleTurningOff")
                refreshBleStatus(FBKBleDeviceStatus.BleTurningOff)
                disconnectBle()
            }
            12 -> {
                showLogInfo("BroadcastReceiver BleTurnOn")
                refreshBleStatus(FBKBleDeviceStatus.BleTurnOn)
            }
            11 -> {
                showLogInfo("BroadcastReceiver BleTurningOn")
                refreshBleStatus(FBKBleDeviceStatus.BleTurningOn)
            }
        }
    }

    private fun initBroadcastReceiver(): BroadcastReceiver {
        return object : BroadcastReceiver() {
            override fun onReceive(context: Context, intent: Intent) {
                val action = intent.action
                showLogInfo("broad cast action $action")
                val device =
                    intent.getParcelableExtra<Parcelable>("android.bluetooth.device.extra.DEVICE") as BluetoothDevice?
                if (bluetoothDeviceInternal == null && bluetoothDeviceInternal != device) {
                    return
                }
                when (action) {
                    ACL_CONNECTED -> showLogInfo("BroadcastReceiver BLE is connected")
                    ACL_DISCONNECTED -> {
                        showLogInfo("BroadcastReceiver BLE is disconnected")
                        refreshBleStatus(FBKBleDeviceStatus.BleDisconnected)
                    }
                    STATE_CHANGED -> handleStateChange(intent)
                }
            }
        }
    }


    private inline fun checkBlePermission(permission: String, block: () -> Unit) {
        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R) {
            if (ActivityCompat.checkSelfPermission(
                    mContext,
                    permission
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                showLogInfo("do not have permission : $permission")
                return
            }
        }
        block()
    }

    override fun onDeviceConnecting(device: BluetoothDevice) {
        refreshBleStatus(FBKBleDeviceStatus.BleConnecting)
    }

    override fun onDeviceConnected(device: BluetoothDevice) {
        Log.e("d","ddd")
        fbkConnection?.requestMTU(55)
    }

    override fun onDeviceFailedToConnect(device: BluetoothDevice, reason: Int) {
        refreshBleStatus(FBKBleDeviceStatus.BleDisconnected)
        mBleControllerCallBack.bleConnectError("onDeviceFailedToConnect${reason}")
    }

    override fun onDeviceReady(device: BluetoothDevice) {
        refreshBleStatus(FBKBleDeviceStatus.BleConnected)
        MainScope().launch {
            delay(1000)
            mBleControllerCallBack.requestTime()
        }
    }

    override fun onDeviceDisconnecting(device: BluetoothDevice) {
        refreshBleStatus(FBKBleDeviceStatus.BleDisconnecting)
    }

    override fun onDeviceDisconnected(device: BluetoothDevice, reason: Int) {
        refreshBleStatus(FBKBleDeviceStatus.BleDisconnected)
    }
}
